package com.googlecode.lookie.platform.status;

import java.awt.Color;
import java.awt.Component;
import java.awt.SystemColor;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;

import org.jdesktop.swingx.JXStatusBar;
import org.jdesktop.swingx.JXStatusBar.Constraint;
import org.springframework.richclient.application.statusbar.StatusBar;
import org.springframework.richclient.application.statusbar.support.StatusBarProgressMonitor;
import org.springframework.richclient.core.Message;
import org.springframework.richclient.factory.AbstractControlFactory;
import org.springframework.richclient.progress.ProgressMonitor;

public class LookieStatusBar
    extends AbstractControlFactory
    implements StatusBar
{

    private String message;

    private String errorMessage;

    private JLabel messageLabel;

    private StatusBarProgressMonitor progressMonitor;

    private JXStatusBar statusBar;

    private MemoryStatus memoryStatus;

    /**
     * Returns the status bar's progress monitor
     */
    public ProgressMonitor getProgressMonitor()
    {
        return progressMonitor;
    }

    /**
     * Controls whether the ProgressIndication provides UI for canceling a long running operation. If the
     * ProgressIndication is currently visible calling this method may have a direct effect on the layout because it
     * will make a cancel button visible.
     */
    public void setCancelEnabled( boolean enabled )
    {
        progressMonitor.setCancelEnabled( enabled );
    }

    /**
     * Sets the message text to be displayed on the status bar.
     * <p>
     * The icon of the message is ignored
     *
     * @param message the message to be set, if <code>null</code>, the status line is cleared.
     */
    public void setMessage( Message message )
    {
        setMessage( message == null ? null : message.getMessage() );
    }

    /**
     * Sets the message text to be displayed on the status bar.
     *
     * @param message the message to be set, if <code>null</code>, the status line is cleared.
     */
    public void setMessage( String message )
    {
        this.message = message;
        if ( errorMessage == null )
        {
            logger.debug( "Setting status bar message to \"" + message + "\"" );
            messageLabel.setText( this.message );
        }
    }

    /**
     * Sets the error message text to be displayed on the status bar.
     * <p>
     * Error messages are shown over the standard message, and in a red color.
     * <p>
     * The icon of the message is ignored
     *
     * @param message the error message to be set, if <code>null</code>, the error message is cleared, and the standard
     *            message is shown again
     */
    public void setErrorMessage( Message errorMessage )
    {
        setErrorMessage( errorMessage == null ? null : errorMessage.getMessage() );
    }

    /**
     * Sets the error message text to be displayed on the status bar.
     * <p>
     * Error messages are shown over the standard message, and in a red color.
     *
     * @param message the error message to be set, if <code>null</code>, the error message is cleared, and the standard
     *            message is shown again
     */
    public void setErrorMessage( String errorMessage )
    {
        if ( errorMessage == null )
        {
            logger.debug( "Resetting the status bar message color to normal" );
            messageLabel.setForeground( SystemColor.controlText );

            this.errorMessage = null;
            setMessage( message );
        }
        else
        {
            logger.debug( "Setting the status bar messsage color to red" );
            messageLabel.setForeground( Color.RED );

            logger.debug( "Setting status bar error message to \"" + errorMessage + "\"" );
            this.errorMessage = errorMessage;
            messageLabel.setText( this.errorMessage );
        }
    }

    @Override
    protected JComponent createControl()
    {
        statusBar = new JXStatusBar();

        messageLabel = createMessageLabel();
        progressMonitor = createStatusBarProgressMonitor();
        memoryStatus = createMemoryStatus();

        Constraint c1 = new Constraint( JXStatusBar.Constraint.ResizeBehavior.FILL );
        // c1.setFixedWidth(200);
        statusBar.add( messageLabel, c1 );
        Constraint c2 = new Constraint( JXStatusBar.Constraint.ResizeBehavior.FIXED );
        c2.setFixedWidth( 200 );
        statusBar.add( progressMonitor.getControl(), c2 );

        Constraint c3 = new Constraint( JXStatusBar.Constraint.ResizeBehavior.FIXED );
        c3.setFixedWidth( 100 );
        statusBar.add( memoryStatus, c3 );

        return statusBar;
    }

    /**
     * Create the <code>JLabel</code> used to render the messages.
     * <p>
     * Can safely be overridden to customize the label
     *
     * @return the <code>JLabel</code>
     */
    protected JLabel createMessageLabel()
    {
        JLabel messageLabel = new JLabel( " " );
        messageLabel.setName( "message" );

        return messageLabel;
    }

    /**
     * Create the <code>StatusBarProgressMonitor</code>.
     * <p>
     * Can safely be overridden to customize the progress monitor and its components
     *
     * @return the <code>StatusBarProgressMonitor</code>
     */
    protected StatusBarProgressMonitor createStatusBarProgressMonitor()
    {
        return new StatusBarProgressMonitor();
    }

    protected MemoryStatus createMemoryStatus()
    {
        MemoryStatus memoryStatus = new MemoryStatus();

        Border bevelBorder = BorderFactory.createBevelBorder( BevelBorder.LOWERED, UIManager
            .getColor( "controlHighlight" ), UIManager.getColor( "controlShadow" ) );
        Border emptyBorder = BorderFactory.createEmptyBorder( 1, 3, 1, 3 );
        memoryStatus.setBorder( BorderFactory.createCompoundBorder( bevelBorder, emptyBorder ) );

        return memoryStatus;
    }

    public void clear()
    {
        setErrorMessage( (String) null );
        setMessage( (String) null );
    }

    /**
     * Shows or hides this status bar.
     *
     * @see Component#setVisible(boolean)
     */
    public void setVisible( boolean visible )
    {
        statusBar.setVisible( visible );
    }

}
